package com.huiminpay.transaction.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.huiminpay.common.cache.domain.BusinessException;
import com.huiminpay.common.cache.domain.CommonErrorCode;
import com.huiminpay.common.cache.util.AmountUtil;
import com.huiminpay.common.cache.util.EncryptUtil;
import com.huiminpay.common.cache.util.PaymentUtil;
import com.huiminpay.merchant.api.AppService;
import com.huiminpay.merchant.api.StoreService;
import com.huiminpay.merchant.dto.AppDTO;
import com.huiminpay.paymentagent.api.PayChannelAgentService;
import com.huiminpay.paymentagent.conf.AliConfigParam;
import com.huiminpay.paymentagent.dto.AlipayBean;
import com.huiminpay.paymentagent.dto.PaymentResponseDTO;
import com.huiminpay.transaction.api.PayChannelService;
import com.huiminpay.transaction.api.TransactionService;
import com.huiminpay.transaction.convert.PayOrderConvert;
import com.huiminpay.transaction.dto.PayChannelParamDTO;
import com.huiminpay.transaction.dto.PayOrderDTO;
import com.huiminpay.transaction.dto.QRCodeDto;
import com.huiminpay.transaction.entity.PayOrder;
import com.huiminpay.transaction.mapper.PayOrderMapper;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Value;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

/**
 * @ClassName: TransactionServiceImpl
 * @Package: com.huiminpay.transaction.service
 * @Description: 交易订单相关服务实现
 * @Author 谢同学
 * @Create 2023/11/29 8:42
 * @Version 1.0
 */
@Service
public class TransactionServiceImpl implements TransactionService {

    @Reference
    AppService appService;
    @Reference
    StoreService storeService;
    @Reference
    PayChannelService payChannelService;
    @Reference
    PayChannelAgentService payChannelAgentService;
    @Resource
    PayOrderMapper payOrderMapper;


    @Value("${huiminpay.payurl}")
    private String payurl;

    /**
     * 生成门店二维码
     *
     * @param qrCodeDto 相关参数（merchantId,appId、storeid、channel、subject、body）
     * @return 支付入口URL，将二维码的参数组成json并用base64编码
     * @throws BusinessException
     */
    @Override
    public String createStoreQRCode(QRCodeDto qrCodeDto) throws BusinessException {
        //检验应用和门店
        verifyAppAndStore(qrCodeDto.getMerchantId(), qrCodeDto.getAppId(), qrCodeDto.getStoreId());


        //生成支付信息
        PayOrderDTO payOrderDTO = new PayOrderDTO();

        payOrderDTO.setMerchantId(qrCodeDto.getMerchantId());
        payOrderDTO.setAppId(qrCodeDto.getAppId());
        payOrderDTO.setStoreId(qrCodeDto.getStoreId());
        payOrderDTO.setSubject(qrCodeDto.getSubject());//显示订单标题
        payOrderDTO.setChannel("huimin_c2b");//服务类型
        payOrderDTO.setBody(qrCodeDto.getBody());//订单内容

        //把信息转为json数据
        String jsonString = JSON.toJSONString(payOrderDTO);

        //将支付信息保存到票据中4
        String ticket = EncryptUtil.encodeUTF8StringBase64(jsonString);//加密

        //拼接支付入口
        String payEntryUrl = payurl + ticket;
        return payEntryUrl;

    }

    /**
     * 支付宝订单保存,调用渠道代理服务
     *
     * @param payOrderDTO 订单信息
     * @return
     * @throws BusinessException
     */
    @Override
    public PaymentResponseDTO submitOrderByAli(PayOrderDTO payOrderDTO) throws BusinessException {
        //保存订单
        //根据appId查询App信息
        AppDTO appDTO = queryAppByAppId(payOrderDTO.getAppId());

        payOrderDTO.setMerchantId(appDTO.getMerchantId());//商户ID
        payOrderDTO.setTradeNo(PaymentUtil.genUniquePayOrderNo());//采用雪花片算法
        payOrderDTO.setPayChannel("ALIPAY_WAP");//原始支付渠道编码
        payOrderDTO.setTradeState("0");//订单状态，0：订单生成
        payOrderDTO.setCurrency("CNY");//币种
        //金额转换 元转分
        payOrderDTO.setTotalAmount(Integer.parseInt(AmountUtil.changeY2F(payOrderDTO.getTotalAmount().toString())));
        payOrderDTO.setCreateTime(LocalDateTime.now());//订单创建时间
        payOrderDTO.setExpireTime(LocalDateTime.now().plus(30, ChronoUnit.MINUTES));//过期时间
        //调用添加
        save(payOrderDTO);

        //调用支付代理服务请求第三方支付系统
        //调用支付渠道代理服务支付宝下单接口
        PaymentResponseDTO paymentResponseDTO = alipayH5(payOrderDTO.getTradeNo());
        return paymentResponseDTO;
    }

    /**
     * 用支付渠道代理服务支付宝下单接口（把渠道参数返回来拿数据）
     * @param tradeNo
     * @return
     */
    private PaymentResponseDTO alipayH5(String tradeNo) {
        //构建支付实体
        AlipayBean alipayBean = new AlipayBean();

        //根据订单号查询订单详情
        PayOrderDTO payOrderDTO = queryPayOrder(tradeNo);
        alipayBean.setOutTradeNo(tradeNo);
        alipayBean.setSubject(payOrderDTO.getSubject());
        String totalAmount = null;//支付宝那边入参是元
        try {
            //将分转成元
            totalAmount = AmountUtil.changeF2Y(payOrderDTO.getTotalAmount().toString());
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(CommonErrorCode.E_300006);
        }
        alipayBean.setTotalAmount(totalAmount);
        alipayBean.setBody(payOrderDTO.getBody());
        alipayBean.setStoreId(payOrderDTO.getStoreId());
        alipayBean.setExpireTime("30m");

        //根据应用、服务类型、支付渠道查询支付渠道参数
        PayChannelParamDTO payChannelParamDTO =
                payChannelService.queryPayChannelParamByAppIdAndPlatformcodeAndPayChannel(payOrderDTO.getAppId(),
                        payOrderDTO.getChannel(), "ALIPAY_WAP");
        if(payChannelParamDTO == null){
            throw new BusinessException(CommonErrorCode.E_300007);
        }
        //支付宝渠道参数
        AliConfigParam aliConfigParam = JSON.parseObject(payChannelParamDTO.getParam(),
                AliConfigParam.class);
        //字符编码
        aliConfigParam.setCharest("utf-8");
        PaymentResponseDTO payOrderResponse = payChannelAgentService
                .createPayOrderByAliWAP(aliConfigParam, alipayBean);
        return payOrderResponse;
    }

    /**
     * 根据订单号查询订单信息
     * @param tradeNo
     * @return
     */
    public PayOrderDTO queryPayOrder(String tradeNo){
        PayOrder payOrder = payOrderMapper.selectOne(new LambdaQueryWrapper<PayOrder>().eq(PayOrder::getTradeNo, tradeNo));
        return PayOrderConvert.INSTANCE.entity2dtoa(payOrder);
    }
    /**
     * 保存订单信息
     * @param payOrderDTO 订单信息
     * @return
     */
    private PayOrderDTO save(PayOrderDTO payOrderDTO) {
        PayOrder payOrder = PayOrderConvert.INSTANCE.dto2entitya(payOrderDTO);

        payOrderMapper.insert(payOrder);
        return PayOrderConvert.INSTANCE.entity2dtoa(payOrder);
    }

    /**
     * 校验应用和门店是否属于当前登录商户
     *
     * @param merchantId 商户id
     * @param appId      应用ID
     * @param storeId    门店Id
     */
    private void verifyAppAndStore(Long merchantId, String appId, Long storeId) {
        //判断应用是否属于当但商户
        if (!appService.queryAppInMerchantId(appId, merchantId)) {
            throw new BusinessException(CommonErrorCode.E_200005);
        }
        //判断当前门店是否属于该商户
        if (!storeService.queryStoreInMerchantId(storeId, merchantId)) {
            throw new BusinessException(CommonErrorCode.E_200006);
        }
    }

    /**
     * 根据appId查询app信息
     *
     * @param appId
     * @return
     */
    private AppDTO queryAppByAppId(String appId) {
        return appService.getAppById(appId);
    }


    /**
     * 更新订单支付状态
     * @param tradeNo  惠民平台订单号
     * @param payChannelTradeNo 支付宝或微信的交易流水号
     * @param state  订单状态 交易状态支付状态,0‐订单生成,1‐支付中(目前未使用),2‐支付成功,4‐关闭 5‐‐失败
     */
    @Override
    public void updateOrderTradeNoAndTradeState(String tradeNo, String payChannelTradeNo, String state) {
        final LambdaUpdateWrapper<PayOrder> lambda = new UpdateWrapper<PayOrder>().lambda();
        lambda.eq(PayOrder::getTradeNo, tradeNo).set(PayOrder::getPayChannelTradeNo, payChannelTradeNo)
                .set(PayOrder::getTradeState, state);
        if (state != null && "2".equals(state)) {
            lambda.set(PayOrder::getPaySuccessTime, LocalDateTime.now());
        }
        payOrderMapper.update(null, lambda);
    }


}
